package com.itmake.webflux.security.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
//import com.itmake.website.basic.util.DateUtil;
//import com.itmake.website.redis.util.RedisUtil;
import com.itmake.webflux.security.constant.JwtConstant;
import com.itmake.webflux.security.constant.TokenConstant;
import com.itmake.webflux.security.model.bo.JwtUserBo;
import com.itmake.webflux.security.property.SecurityProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * token 服务
 *
 * @author Amjacks
 * @since 2023/08/10
 */
@Component
public class TokenService {

    // 令牌有效期
    @Autowired
    private SecurityProperty securityProperty;

    @Autowired
//    private RedisUtil redisUtil;

    /**
     * 获取请求 token
     */
    public String getToken(ServerHttpRequest request) {
        // 获取请求携带的令牌
        String token = request.getHeaders().getFirst(TokenConstant.HEADER);
        // 去除 token 前缀
        if (CharSequenceUtil.isNotBlank(token) && token.startsWith(TokenConstant.PREFIX)) {
            token = token.replace(TokenConstant.PREFIX, CharSequenceUtil.EMPTY);
        }
        return token;
    }

    /**
     * 构建 token key
     */
    private String buildTokenKey(String os, String username) {
        return TokenConstant.TOKEN_REDIS_KEY + username + ":" + os;
    }

    /**
     * 创建令牌
     *
     * @param jwtUserBo 用户信息
     * @return 令牌
     */
    public String create(JwtUserBo jwtUserBo) {
        Map<String, Object> map = new HashMap<>();
        // 用户名称
        map.put(JwtConstant.USERNAME, jwtUserBo.getUsername());
        // 权限
        List<String> collect = jwtUserBo.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(collect)) {
            map.put(JwtConstant.AUTHORITIES, ArrayUtil.join(collect.toArray(), ","));
        }
        // 操作系统
        map.put(JwtConstant.OS, jwtUserBo.getOs());
        // 浏览器
        map.put(JwtConstant.BROWSER, jwtUserBo.getBrowser());
        // 登录 IP 地址
        map.put(JwtConstant.LOGIN_IP, jwtUserBo.getLoginIp());
        // 登录时间
        map.put(JwtConstant.LOGIN_TIME, jwtUserBo.getLoginTime());
        // 生成令牌
        return refresh(map);
    }

    /**
     * 验证令牌有效期
     */
    public String verify(ServerHttpRequest request) {
        String token = null;
        final JWT jwt = JWTUtil.parseToken(getToken(request));
        long expire = Long.parseLong(String.valueOf(jwt.getPayload(JwtConstant.EXPIRE_TIME)));
        if (expire - System.currentTimeMillis() <= securityProperty.getRefreshTime() * TokenConstant.MILLIS_MINUTE) {
            // 刷新令牌
            token = refresh(jwt.getPayloads());
        }
        return token;
    }

    /**
     * 验证令牌缓存
     */
    public Boolean verifyCache(ServerHttpRequest request) {
        JwtUserBo user = getUser(request);
//        String token = redisUtil.getCacheObject(buildTokenKey(user.getOs(), user.getUsername()));
        String token = "";
        return CharSequenceUtil.isNotBlank(token) && token.equals(getToken(request));
    }

    /**
     * 刷新令牌
     */
    public String refresh(ServerHttpRequest request) {
        return refresh(JWTUtil.parseToken(getToken(request)).getPayloads());
    }

    /**
     * 获取用户名
     */
    public String getUsername(ServerHttpRequest request) {
        return String.valueOf(JWTUtil.parseToken(getToken(request)).getPayload(JwtConstant.USERNAME));
    }

    /**
     * 获取用户
     */
    public JwtUserBo getUser(ServerHttpRequest request) {
        JWT jwt = JWTUtil.parseToken(getToken(request));
        JwtUserBo jwtUserBo = new JwtUserBo();
        // 用户名
        jwtUserBo.setUsername(String.valueOf(jwt.getPayload(JwtConstant.USERNAME)));
        // 权限
        Object payload = jwt.getPayload(JwtConstant.AUTHORITIES);
        List<GrantedAuthority> authorityList = new ArrayList<>();
        if (Objects.nonNull(payload)) {
            String authorities = String.valueOf(payload);
            String[] split = authorities.split(",");
            for(String permission : split){
                GrantedAuthority authority = new SimpleGrantedAuthority(permission);
                authorityList.add(authority);
            }
        }
        jwtUserBo.setAuthorities(authorityList);
        // OS
        jwtUserBo.setOs(String.valueOf(jwt.getPayload(JwtConstant.OS)));
        // 登录 IP 地址
        jwtUserBo.setLoginIp(String.valueOf(jwt.getPayload(JwtConstant.LOGIN_IP)));
        // 登录时间
//        jwtUserBo.setLoginTime(DateUtil.parseInstant(String.valueOf(jwt.getPayload(JwtConstant.LOGIN_TIME))));
        return jwtUserBo;
    }

    /**
     * 验证 token
     */
    public boolean verifyToken(ServerHttpRequest request) {
        // 获取请求携带的令牌
        String token = getToken(request);
        // 非空，并验证 token 合法性
        return CharSequenceUtil.isNotBlank(token) && JWTUtil.verify(token, securityProperty.getSecret().getBytes());
    }

    /******************* redis 操作 *******************/
    /**
     * 刷新令牌
     */
    private String refresh(Map<String, Object> map) {
        // 过期时间
        map.put(JwtConstant.EXPIRE_TIME, System.currentTimeMillis() + securityProperty.getExpireTime() * TokenConstant.MILLIS_MINUTE);
        // 生成令牌
        String token = JWTUtil.createToken(map, securityProperty.getSecret().getBytes());
        // 缓存
        /*redisUtil.setCacheObject(buildTokenKey(String.valueOf(map.get(JwtConstant.OS)), String.valueOf(map.get(JwtConstant.USERNAME))),
                token, securityProperty.getExpireTime(), TimeUnit.MINUTES);*/
        // 返回令牌
        return token;
    }

    /**
     * 删除用户登录信息
     */
    public void delete(String os, String username) {
        if (CharSequenceUtil.isNotBlank(os) && CharSequenceUtil.isNotBlank(username)) {
//            redisUtil.deleteObject(buildTokenKey(os, username));
        }
    }

    /**
     * 删除当前用户登录信息
     */
    public void delete(ServerHttpRequest request) {
        JwtUserBo user = getUser(request);
//        redisUtil.deleteObject(buildTokenKey(user.getOs(), user.getUsername()));
    }
}
